/************************************************************************
* Programmer:  Philippe Gambling
*
* Course:  CSCI 4534
*
* Date:  April 15, 2009
*
* Environment:  GCC 3.2.2 running on diamond.rocks.uhcl.edu
*
* Files Included: memory.h, memory.c
*
* Purpose:  Implements a simulated memory structure.
*
***********************************************************************/ 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "memory.h"


Memory new_Memory(int size) 
{
/************************************************************************
* Purpose:  To create a new Memory object
*
* Parameters:  (int) size, the number of memory units available.
*
* Action:  Allocates and returns a new Memory object.
*
***********************************************************************/
  Memory m = (Memory)malloc(sizeof(struct memory));
  if(m == NULL) { return NULL; }

  m->_isize = size;
  m->_pdata = (char *)malloc((size+1)*sizeof(char));
  memset(m->_pdata,'\0',size+1);    
  memset(m->_pdata,'/',size);
  
  return m;
}

void free_Memory(Memory m) 
{
/************************************************************************
* Purpose:  To free up memory associated with Memory.
*
* Parameters:  (Memory) target Memory.
*
* Action:  Free memory pointed to by _pdata, and frees the node memory
*
***********************************************************************/
  free(m->_pdata); m->_pdata = NULL;
  free(m); m = NULL;
}

unsigned int Memory_Size(const Memory m)
{
/************************************************************************
* Purpose:  To return the size of this memory object.
*
* Parameters:  (Memory) target Memory
*
* Action:  Use memcpy to copy size bytes of data from _pdata to dest.
*
***********************************************************************/
  return m->_isize;
}

void Memory_Print(const Memory m, char * ret)
{
/************************************************************************
* Purpose:  To print the contents of memory.
*
* Parameters:  (Memory) target Memory, (char *) returns copy of _pdata
*
* Action:  Prints the memory to the console
*          and returns a copy of_pdata through ret
*
***********************************************************************/
  int i = 0;
  printf("Memory map ('/' indicates a free space)\n");
  printf("Addr Contents");
  for(i=0;i<m->_isize;i++) {
    if(i%5 == 0) { printf("\n%02d - ",i); }  
    printf("%c",m->_pdata[i]);
  }
  printf("\n");
  if(ret) { strcpy(ret,m->_pdata); }
}

unsigned int Memory_Allocate(const Memory m, const int size, const char id)
{
/************************************************************************
* Purpose:  To assign memory to id if available is >= size
*
* Parameters:  (const Memory) target Memory, (char int) request size, 
*              (const char) process id to assign memory to
*
* Action:  Looks through _pdata for enough contiguous memory spaces to 
*          satisfy request of size length, returns true if successful
*          or false if unable to allocate memory.
*
***********************************************************************/
  unsigned int retval = FALSE; 
  char * searchStr = NULL; // Holds string used to search _pdata for hole
  char * hole = NULL; // Pointer to hold in _pdata
  
  // Fail immediately if request is larger than memory
  if(size > m->_isize) { return retval; }
  
  // Build a string that matches the hole size requested
  searchStr = (char *) malloc(sizeof(char)*(size+1));
  memset(searchStr,'\0',size+1);
  memset(searchStr,'/',size);
    
  // Find first available hole  
  hole = strstr(m->_pdata,searchStr);
  if(hole == NULL) { retval = FALSE; }
  else {
    memset(hole,id,size); // Assign hole to process id
    retval = TRUE;
  }    
 
  // Clean up and exit 
  free(searchStr); searchStr = NULL; 
  return retval;
}

unsigned int Memory_Deallocate(const Memory m, const char id)
{
/************************************************************************
* Purpose:  To unassign memory from id if it exists
*
* Parameters:  (const Memory) target Memory,
*              (const char) process id to free from memory
*
* Action:  Sets all instances of id to '/' in _pdata. Returns true if 
*          if found, false otherwise.
*
***********************************************************************/
  unsigned int retval = FALSE;
  int i=0;

  for(i=0; i < m->_isize; i++) {
    if(m->_pdata[i] == id) {
      m->_pdata[i] = '/';
      retval = TRUE;
    }
  }
  
  return retval;
}
